home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
rpg
/
crossfir.92
/
crossfir
/
crossfire-0.92.5
/
server
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-24
|
26KB
|
873 lines
/*
* static char *rcsid_main_c =
* "$Id: main.c,v 1.36 1996/01/02 11:44:23 master Exp $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 1994 Mark Wedel
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author can be reached via e-mail to master@rahul.net
*/
#if ((defined(__sun__) || defined(__sgi)) && defined(SVR4))
#include <crypt.h>
#endif
#if defined(__osf__)
/* <crypt.h> declares crypt_r(), but not crypt() !?! (OSF/1 1.0) */
extern char *crypt(const char *, const char *);
#endif
#include <version.h>
#include <global.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
#include <main.h>
#include <object.h>
#if defined (_IBMR2) || defined (___IBMR2) /* Which is correct? */
#include <time.h>
#endif
static char days[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
void version(object *op) {
if(op!=NULL)
clear_win_info(op);
new_draw_info_format(NDI_UNIQUE, 0, op, "This is Crossfire v%s%s",VERSION,PATCH);
/* If in a socket, don't print out the list of authors. It confuses the
* crossclient program.
*/
if (op==NULL) return;
new_draw_info(NDI_UNIQUE, 0,op,"Authors and contributors to this program:");
new_draw_info(NDI_UNIQUE, 0,op,"master@rahul.net (Mark Wedel)");
new_draw_info(NDI_UNIQUE, 0,op,"frankj@ifi.uio.no (Frank Tore Johansen)");
new_draw_info(NDI_UNIQUE, 0,op,"kjetilho@ifi.uio.no (Kjetil Torgrim Homme)");
new_draw_info(NDI_UNIQUE, 0,op,"tvangod@ecst.csuchico.edu (Tyler Van Gorder)");
new_draw_info(NDI_UNIQUE, 0,op,"elmroth@cd.chalmers.se (Tony Elmroth)");
new_draw_info(NDI_UNIQUE, 0,op,"dougal.scott@fcit.monasu.edu.au (Dougal Scott)");
new_draw_info(NDI_UNIQUE, 0,op,"wchuang@athena.mit.edu (William)");
new_draw_info(NDI_UNIQUE, 0,op,"ftww@cs.su.oz.au (Geoff Bailey)");
new_draw_info(NDI_UNIQUE, 0,op,"jorgens@flipper.pvv.unit.no (Kjetil Wiekhorst Jxrgensen)");
new_draw_info(NDI_UNIQUE, 0,op,"c.blackwood@rdt.monash.edu.au (Cameron Blackwood)");
new_draw_info(NDI_UNIQUE, 0,op,"jtraub+@cmu.edu (Joseph L. Traub)");
new_draw_info(NDI_UNIQUE, 0,op,"rgg@aaii.oz.au (Rupert G. Goldie)");
new_draw_info(NDI_UNIQUE, 0,op,"eanders+@cmu.edu (Eric A. Anderson)");
new_draw_info(NDI_UNIQUE, 0,op,"eneq@Prag.DoCS.UU.SE (Rickard Eneqvist)");
new_draw_info(NDI_UNIQUE, 0,op,"Jarkko.Sonninen@lut.fi (Jarkko Sonninen)");
new_draw_info(NDI_UNIQUE, 0,op,"kholland@sunlab.cit.cornell.du (Karl Holland)");
new_draw_info(NDI_UNIQUE, 0,op,"vick@bern.docs.uu.se (Mikael Lundgren)");
new_draw_info(NDI_UNIQUE, 0,op,"mol@meryl.csd.uu.se (Mikael Olsson)");
new_draw_info(NDI_UNIQUE, 0,op,"Tero.Haatanen@lut.fi (Tero Haatanen)");
new_draw_info(NDI_UNIQUE, 0,op,"ylitalo@student.docs.uu.se (Lasse Ylitalo)");
new_draw_info(NDI_UNIQUE, 0,op,"anipa@guru.magic.fi (Niilo Neuvo)");
new_draw_info(NDI_UNIQUE, 0,op,"mta@modeemi.cs.tut.fi (Markku J{rvinen)");
new_draw_info(NDI_UNIQUE, 0,op,"meunier@inf.enst.fr (Sylvain Meunier)");
new_draw_info(NDI_UNIQUE, 0,op,"jfosback@darmok.uoregon.edu (Jason Fosback)");
new_draw_info(NDI_UNIQUE, 0,op,"cedman@capitalist.princeton.edu (Carl Edman)");
new_draw_info(NDI_UNIQUE, 0,op,"henrich@crh.cl.msu.edu (Charles Henrich)");
new_draw_info(NDI_UNIQUE, 0,op,"schmid@fb3-s7.math.tu-berlin.de (Gregor Schmid)");
new_draw_info(NDI_UNIQUE, 0,op,"quinet@montefiore.ulg.ac.be (Raphael Quinet)");
new_draw_info(NDI_UNIQUE, 0,op,"jam@modeemi.cs.tut.fi (Jari Vanhala)");
new_draw_info(NDI_UNIQUE, 0,op,"kivinen@joker.cs.hut.fi (Tero Kivinen)");
new_draw_info(NDI_UNIQUE, 0,op,"peterm@soda.berkeley.edu (Peter Mardahl)");
new_draw_info(NDI_UNIQUE, 0,op,"matt@cs.odu.edu (Matthew Zeher)");
new_draw_info(NDI_UNIQUE, 0,op,"srt@sun-dimas.aero.org (Scott R. Turner)");
new_draw_info(NDI_UNIQUE, 0,op,"huma@netcom.com (Ben Fennema)");
new_draw_info(NDI_UNIQUE, 0,op,"njw@cs.city.ac.uk (Nick Williams)");
new_draw_info(NDI_UNIQUE, 0,op,"Wacren@Gin.ObsPM.Fr (Laurent Wacrenier)");
new_draw_info(NDI_UNIQUE, 0,op,"thomas@astro.psu.edu (Brian Thomas)");
new_draw_info(NDI_UNIQUE, 0,op,"jsm@axon.ksc.nasa.gov (John Steven Moerk)");
}
void info_keys(object *op) {
clear_win_info(op);
new_draw_info(NDI_UNIQUE, 0,op,"Push `hjklynub' to walk in a direction.");
new_draw_info(NDI_UNIQUE, 0,op,"Shift + dir = fire, Ctrl + dir = run");
new_draw_info(NDI_UNIQUE, 0,op,"(To fire at yourself, hit `.'");
new_draw_info(NDI_UNIQUE, 0,op,"To attack, walk into the monsters.");
new_draw_info(NDI_UNIQUE, 0,op,"\" = speak ' = extended command");
new_draw_info(NDI_UNIQUE, 0,op,"i = inventory , = get : = look");
new_draw_info(NDI_UNIQUE, 0,op,"<> = rotate d = drop ? = help");
new_draw_info(NDI_UNIQUE, 0,op,"a = apply A = apply below t = throw");
new_draw_info(NDI_UNIQUE, 0,op,"e = examine E = exa below @ = autopick");
new_draw_info(NDI_UNIQUE, 0,op,"C = configure s = brace v = version");
new_draw_info(NDI_UNIQUE, 0,op,"+- = change range <tab> = browse spells");
new_draw_info(NDI_UNIQUE, 0,op,"x = change inventory type");
#ifdef SAVE_WINDOW_POSITIONS
new_draw_info(NDI_UNIQUE, 0,op,"X = Toggle window position saving.");
#endif /* SAVE_WINDOW_POSITIONS */
new_draw_info(NDI_UNIQUE, 0,op,"Mouse: L = examine, M = apply, R = drop/get");
new_draw_info(NDI_UNIQUE, 0,op,"'help = info about extended commands.");
new_draw_info(NDI_UNIQUE, 0,op,"Ctrl-R = refresh Ctrl-C = clear");
new_draw_info(NDI_UNIQUE, 0,op,"You can type a number before most commands.");
new_draw_info(NDI_UNIQUE, 0,op,"(For instance 3d drops 3 items.)");
}
void start_info(object *op) {
char buf[MAX_BUF];
sprintf(buf,"Welcome to Crossfire, v%s%s!",VERSION,PATCH);
new_draw_info(NDI_UNIQUE, 0,op,buf);
new_draw_info(NDI_UNIQUE, 0,op,"Press `?' for help");
new_draw_info(NDI_UNIQUE, 0,op," ");
new_draw_info_format(NDI_UNIQUE | NDI_ALL, 5, op,
"%s entered the game.",op->name);
if(!op->contr->name_changed) {
new_draw_info(NDI_UNIQUE, 0,op,"Note that you must set your name with the name");
new_draw_info(NDI_UNIQUE, 0,op,"command to enter the highscore list.");
new_draw_info(NDI_UNIQUE, 0,op,"(You can also use the crossfire.name X-resource.)");
}
}
char *crypt_string(char *str, char *salt) {
static char *c=
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
char s[2];
if(salt==NULL)
s[0]= c[RANDOM() % (int)strlen(c)],
s[1]= c[RANDOM() % (int)strlen(c)];
else
s[0]= salt[0],
s[1]= salt[1];
return crypt(str,s);
}
int check_password(char *typed,char *crypted) {
return !strcmp(crypt_string(typed,crypted),crypted);
}
char *normalize_path (char *src, char *dst) {
char *p, *q;
char buf[MAX_BUF];
static char path[MAX_BUF];
/* LOG(llevDebug,"path before normalization >%s<>%s<\n", src, dst); */
if (*dst == '/') {
strcpy (buf, dst);
} else {
strcpy (buf, src);
if ((p = strrchr (buf, '/')))
p[1] = '\0';
else
strcpy (buf, "/");
strcat (buf, dst);
}
q = p = buf;
while ((q = strstr (q, "//")))
p = ++q;
*path = '\0';
q = path;
p = strtok (p, "/");
while (p) {
if (!strcmp (p, "..")) {
q = strrchr (path, '/');
if (q)
*q = '\0';
else {
*path = '\0';
LOG (llevError, "Illegal path.\n");
}
} else {
strcat (path, "/");
strcat (path, p);
}
p = strtok (NULL, "/");
}
/* LOG(llevDebug,"path after normalization >%s<\n", path); */
return (path);
}
/* Tries to move 'op' to exit_ob. op is the character or monster that is
* using the exit, where exit_ob is the exit object (boat, door, teleporter,
* etc.) if exit_ob is null, then op->maplevel contains that map to
* move the object to (and use default map coordiantes
*/
void enter_exit(object *op, object *exit_ob) {
char buf[MAX_BUF];
/* having dummy_map be non static is better for two reasons - with it
* being static, only 1 instance of it was created, and thus, if this
* function was called recursively, dummy_map would not have an
* expected value. Second, dummy_map is no longer needed once this
* function finishes, and as I understand it, its data will be accessible
* until that time --MSW
*/
mapstruct *m, dummy_map;
int x=0, y=0, removed=QUERY_FLAG(op,FLAG_REMOVED);
char *newpath=NULL, *lastlevel=NULL;
int oldx = (-1), oldy = (-1), last_x = op->x, last_y = op->y;
dummy_map.pending = (objectlink *) NULL;
dummy_map.in_memory = MAP_LOADING;
if (exit_ob) {
x=EXIT_X(exit_ob);
y=EXIT_Y(exit_ob);
if (EXIT_PATH(exit_ob)) {
newpath = normalize_path (exit_ob->map->path, EXIT_PATH(exit_ob));
} else {
if (EXIT_LEVEL (exit_ob) > 0)
LOG(llevError,"Number Map levels are no more supported\n");
}
} else
newpath = op->contr->maplevel;
/* If no map path has been found yet, just keep the player on the
* map he is on right now
*/
if(!newpath)
newpath = op->map->path;
/* See if the map actually exists */
if (!has_been_loaded(newpath) && check_path(newpath) == -1) {
sprintf(buf,"The %s is closed.", exit_ob->name);
new_draw_info(NDI_UNIQUE, 0,op, buf);
return;
}
/* Clear the player's count, and reset direction */
op->direction=0;
op->contr->count=0;
op->contr->count_left=0;
if(exit_ob && exit_ob->stats.dam && op->type==PLAYER)
hit_player(op,exit_ob->stats.dam,exit_ob,exit_ob->attacktype);
/* Keep track of the map the player is on right now */
m=op->map;
/* When logging in, the object is already removed. If that is
* not the case, then the following is used */
if(!removed) {
remove_ob(op);
lastlevel = m->path;
op->map = NULL;
if(strcmp (newpath, m->path)) {
/* Remove any golems */
if(op->contr->golem) {
remove_friendly_object(op->contr->golem);
remove_ob(op->contr->golem);
free_object(op->contr->golem);
op->contr->golem=NULL;
}
/* This stuff should probably be moved to ready_map: */
op->map = &dummy_map;
#if MAP_MAXTIMEOUT
m->timeout = MAP_TIMEOUT(m);
if (m->timeout > MAP_MAXTIMEOUT) {
m->timeout = MAP_MAXTIMEOUT;
}
swap_below_max (newpath);
/* Swap out the oldest map if low on mem */
#else
swap_map(m);
#endif
}
m->players--;
}
/* Do any processing to get the map loaded and ready */
op->map = ready_map_name(newpath,0);
/*LOG(llevDebug, "enter_exit: %s\n", newpath); */
if (op->map==NULL) { /* Something went wrong, try to go back */
int x2,y2;
object *enc;
LOG(llevError,"Error, couldn't open map %s.\n", newpath);
op->map = ready_map_name (lastlevel, 0);
x = last_x;
y = last_y;
oldx = op->x, oldy = op->y;
LOG(llevDebug, "Trying to remove all entries to the map.\n");
for (x2 = (-2); x2 < 3; x2++)
for (y2 = (-2); y2 < 3; y2++) {
if (out_of_map(op->map, x2 + op->x, y2 + op->y))
continue;
enc = get_map_ob(op->map, x2 + op->x, y2 + op->y);
if (!enc)
continue;
if (enc->type != ENCOUNTER || enc->slaying == NULL ||
strcmp(enc->slaying, newpath))
continue;
free_string(enc->slaying);
enc->slaying = (char *) NULL;
}
}
#if 0 /* Are these lines really needed? What map a player is on can
* be found out with the maps command anyway.
*/
else if(exit_ob!=NULL && exit_ob->name) {
new_draw_info_format(NDI_UNIQUE | NDI_ALL, 0, op,
"%s enters %s.",op->name,exit_ob->name);
} else {
new_draw_info_format(NDI_UNIQUE | NDI_ALL, 0, op,
"%s teleports to level %s.",op->name,
op->map->map_object->name);
}
#endif
/* new_draw_info(NDI_UNIQUE, 0,op, buf);*/
op->map->players++;
/* If objects are being updated while the map is loading, things like
* pets will be put into the players map, pending element. That is
* really just the dummy_map. Since the map has actually loaded now,
* we want to append that list to the 'real' loaded maps pending
* list -- MSW
*/
if(dummy_map.pending != (objectlink *) NULL) {
objectlink *obl;
for(obl = op->map->pending; obl!= NULL && obl->next != NULL;
obl=obl->next);
if(obl == NULL)
op->map->pending = dummy_map.pending;
else
obl->next = dummy_map.pending;
}
op->contr->loading = op->map;
if (oldx != (-1)) {
op->contr->new_x = oldx;
op->contr->new_y = oldy;
} else {
op->contr->new_x = x;
op->contr->new_y = y;
}
op->contr->removed = removed;
op->map->timeout = 0;
/* I don't think, at least the way things are now, that this can ever
* happen.
*/
if(op->map->in_memory == MAP_LOADING) {
LOG(llevDebug, "Players map is still loading!?\n");
return; /* This will block the player until map has been loaded */
}
#ifdef USE_LIGHTING
if(op->lights||op->glow_radius>0) remove_carried_lights(op,m);
#endif
enter_map(op);
}
/*
* enter_map(): handles the final stages of entering a new map.
*/
void enter_map(object *op) {
op->map = op->contr->loading;
op->contr->loading = NULL;
if((op->contr->new_x || op->contr->new_y) &&
!out_of_map(op->map,op->contr->new_x,op->contr->new_y))
op->x = op->contr->new_x, op->y = op->contr->new_y;
else {
int i = find_free_spot(op->arch,op->map,
EXIT_X(op->map->map_object),
EXIT_Y(op->map->map_object),1,9);
op->x = EXIT_X(op->map->map_object) + freearr_x[i];
op->y = EXIT_Y(op->map->map_object) + freearr_y[i];
}
if(!op->contr->removed) {
SET_FLAG(op, FLAG_NO_APPLY);
insert_ob_in_map(op,op->map);
CLEAR_FLAG(op, FLAG_NO_APPLY);
}
op->enemy = NULL;
#if 0
op->contr->drawn[5][5].number = 0;
/*
* draw_colorpix routine cannot find out, if the background of player has
* changed, and would not redraw player...
*/
#endif
#ifdef USE_LIGHTING
if(op->lights) add_carried_lights(op);
#endif
enter_pending_objects(op->map);
}
/*
* process_active_maps(): Works like process_events(), but it only
* processes maps which are loaded and readied.
* It will check that it isn't called too often, and abort
* if time since last call is less than MAX_TIME.
*
*/
void process_active_maps() {
mapstruct *map;
#if 0
/* Even in single player mode, it is nice to still be able to do stuff
* while a map is saving.
*/
if(first_player==NULL || first_player->next==NULL)
return; /* No point in the following in one-player mode */
#endif
/*
* If enough time has elapsed, do some work.
*/
if(enough_elapsed_time())
for(map=first_map;map!=NULL;map=map->next)
if(map->in_memory == MAP_IN_MEMORY) {
if(players_on_map(map)==0)
continue;
process_events(map);
}
}
#if 0
/* process_events has been extended to take a map arguement, and
* if that is non null, only process objects on that map. As such,
* process_map is no longer needed.
*/
/*
* process_map(map): works like process_events(), but it only processes
* objects within the map 'map'.
*/
void process_map(mapstruct *map) {
int flag;
object *op, *next;
process_players1(map);
for(op=objects;op!=NULL;op=next) {
if(QUERY_FLAG(op, FLAG_FREED)) { /* Was this object somehow freed as a result of */
/* the actions of the previous object? */
flag=0;
break;
}
next=op->next;
if(op->map!=map || op->type == PLAYER)
continue;
if (op->last_anim>=op->anim_speed && op->anim_speed != 0) {
animate_object(op);
op->last_anim=1;
} else op->last_anim++;
#ifdef CASTING_TIME
if (op->casting > 0){
op->casting--;
}
#endif
if(op->speed_left>0) {
--op->speed_left;
if(process_object(op))
continue;
}
}
/* Now go through all objects and give them new speed */
for(op=objects;op!=NULL;op=op->next)
if(op->map==map&&op->speed&&op->speed_left<=0)
op->speed_left+=op->speed>0?op->speed:-op->speed;
process_players2(map);
}
#endif
/* process_players1 and process_players2 do all the player related stuff.
* I moved it out of process events and process_map. This was to some
* extent for debugging as well as to get a better idea of the time used
* by the various functions. process_players1() does the processing before
* objects have been updated, procesS_players2() does the processing that
* is needed after the players have been updated.
*/
void process_players1(mapstruct *map)
{
int flag;
player *pl,*plnext;
for(flag=1;flag!=0;) {
flag=0;
for(pl=first_player;pl!=NULL;pl=plnext) {
plnext=pl->next; /* In case a player exits the game in handle_player() */
if (map!=NULL && (pl->ob == NULL || pl->ob->map!=map)) continue;
#ifdef AUTOSAVE
/* check for ST_PLAYING state so that we don't try to save off when
* the player is logging in.
*/
if ((pl->last_save_tick+AUTOSAVE)<pticks && pl->state==ST_PLAYING) {
save_player(pl->ob,1);
pl->last_save_tick = pticks;
}
#endif
if(pl->ob->speed_left>0) {
if (pl->eric_server>0) {
if (handle_newcs_player(pl->ob))
flag=1;
}
else {
if(--(pl->ob->speed_left)>0) /* Another loop needed */
flag=1;
handle_player(pl->ob);
}
}
}
}
for(pl=first_player;pl!=NULL;pl=pl->next) {
if (map!=NULL && (pl->ob == NULL || pl->ob->map!=map)) continue;
#ifdef CASTING_TIME
if (pl->ob->casting > 0){
pl->ob->casting--;
pl->ob->start_holding = 1;
}
/* set spell_state so we can update the range in stats field */
if ((pl->ob->casting == 0) && (pl->ob->start_holding ==1)){
pl->ob->start_holding = 0;
pl->ob->spell_state = 1;
}
#endif
do_some_living(pl->ob);
draw(pl->ob);
}
}
void process_players2(mapstruct *map)
{
player *pl;
/* Then check if any players should use weapon-speed instead of speed */
for(pl=first_player;pl!=NULL;pl=pl->next) {
if (map!=NULL) {
if(pl->ob == NULL || QUERY_FLAG(pl->ob,FLAG_REMOVED))
continue;
else if(pl->loading != NULL) /* Player is blocked */
pl->ob->speed_left -= pl->ob->speed;
if (pl->ob->map!=map) continue;
}
#ifdef SOUND_EFFECTS
if (pl->play_count > 0)
pl->play_count--;
#endif
if(pl->has_hit) {
float hit_speed = pl->ob->speed/pl->weapon_sp - pl->ob->speed;
if (hit_speed<pl->ob->speed) hit_speed = pl->ob->speed;
pl->ob->speed_left+=hit_speed;
/* This could happen if the player still has left over speed */
if (pl->ob->speed_left>hit_speed) pl->ob->speed_left=hit_speed;
}
else if (pl->ob->speed_left>pl->ob->speed)
pl->ob->speed_left = pl->ob->speed;
}
/* Then synchronize the different screens to avoid jerky movement */
for(pl=first_player;pl!=NULL;pl=pl->next) {
if (pl->eric_server > 0) {
esrv_bar(pl->eric_server,"sync");
continue;
}
if (pl->sync && ++pl->cur_sync >= pl->sync) {
XSync(pl->gdisp,False);
pl->cur_sync = 0;
}
else
XFlush(pl->gdisp);
}
}
#define SPEED_DEBUG
#define NEW_PROCESS_EVENTS
/*
* Withe NEW_PROCESS_EVENTS, this function no longer hogs as much
* cpu time as it did.
* Extended to take a map arguement. This way, process_map is no
* longer needed.
*/
void process_events(mapstruct *map) {
object *op, *next;
process_players1(map);
#ifdef NEW_PROCESS_EVENTS
for (op=active_objects; op!=NULL; op=next) {
#else
for(op=objects;op!=NULL;op=next) {
#endif
if(QUERY_FLAG(op, FLAG_FREED)) { /* Was this object somehow freed as a result of */
/* the actions of the previous object? */
LOG(llevDebug,"Free object on list, process_events\n");
/* break;*/
}
#ifdef NEW_PROCESS_EVENTS
next=op->active_next;
#else
next=op->next;
#endif
if (op->map == NULL && op->env == NULL && op->name &&
op->type!=MAP && map==NULL)
{
LOG(llevError, "Object without map or inventory: %s (%d)\n",
op->name, op->count);
continue;
}
if (map!=NULL && op->map!=map)
continue;
if(!op->speed) {
#ifdef NEW_PROCESS_EVENTS
/* This is not a real problem, unless it repeats for the the same
* object. IF it just gets printed once, it likely means that that
* object was killed/changed by the previous object
*/
LOG(llevDebug, "Object %s has no speed, but is on active list\n",
op->arch->name);
#endif
continue;
}
#if defined(SPEED_DEBUG) && !defined(NEW_PROCESS_EVENTS)
if (op->active_prev==NULL && op->active_next==NULL)
LOG(llevDebug, "Object %s has speed, but not on active list\n", op->arch->name);
#endif
/* Eneq(@csd.uu.se): Handle archetype-field anim_speed differently when
it comes to the animation. If we have a value on this we don't animate it
at speed-events. */
if (op->anim_speed && op->last_anim>=op->anim_speed) {
animate_object(op);
op->last_anim=1;
} else op->last_anim++;
if(op->speed_left>0) {
--op->speed_left;
process_object(op);
}
#ifdef CASTING_TIME
if (op->casting > 0)
op->casting--;
#endif
if (op->speed_left <= 0)
op->speed_left+=(op->speed>0?op->speed:-op->speed);
}
process_players2(map);
}
void clean_tmp_files() {
mapstruct *m;
player *pl;
LOG(llevError,"Cleaning up...\n");
for(pl=first_player;pl!=NULL;pl=pl->next)
remove_lock(pl);
for(m=first_map;m!=NULL;m=m->next)
clean_tmp_map(m);
#if defined(UNIQUE_ITEMS) && defined(LOCK_ITEMS)
clean_lockfiles();
#endif
}
void leave(player *pl) {
char buf[MAX_BUF];
/* Lets free this before you close the connection */
if (pl->pixmaps) free_pixmaps(pl->gdisp, pl->pixmaps);
if (pl->masks) free_pixmaps(pl->gdisp, pl->masks);
if (pl->eric_server > 0)
esrv_remove_player(pl->eric_server);
else {
XSync(pl->gdisp, False);
/* Free all the GCs we made */
if(pl->gc_root)
XFreeGC(pl->gdisp, pl->gc_root);
if(pl->gc_game)
XFreeGC(pl->gdisp, pl->gc_game);
if(pl->gc_stats)
XFreeGC(pl->gdisp, pl->gc_stats);
if(pl->gc_info)
XFreeGC(pl->gdisp, pl->gc_info);
if(pl->gc_inv_text)
XFreeGC(pl->gdisp, pl->gc_inv_text);
if(pl->gc_inv_icon)
XFreeGC(pl->gdisp, pl->gc_inv_icon);
if(pl->gc_look_text)
XFreeGC(pl->gdisp, pl->gc_look_text);
if(pl->gc_look_icon)
XFreeGC(pl->gdisp, pl->gc_look_icon);
if(pl->gc_message)
XFreeGC(pl->gdisp, pl->gc_message);
if(pl->gc_xpm_floor)
XFreeGC(pl->gdisp, pl->gc_xpm_floor);
if(pl->gc_xpm_object)
XFreeGC(pl->gdisp, pl->gc_xpm_object);
XDestroyWindow(pl->gdisp,pl->win_game);
XCloseDisplay(pl->gdisp);
}
(void) sprintf(buf,"%s left the game.",pl->name);
if (pl->ob->map->in_memory==MAP_IN_MEMORY)
pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map);
pl->ob->map->players--;
pl->ob->map=NULL;
pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
free_player(pl);
#ifdef SERVER
if(server_mode != SERVER_ENABLED)
#endif
if(first_player==NULL) { /* Last player left the game */
clean_tmp_files();
exit(0);
}
new_draw_info(NDI_UNIQUE | NDI_ALL, 5, NULL, buf);
}
int forbid_play()
{
#if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
char buf[MAX_BUF], day[MAX_BUF];
FILE *fp;
time_t clock;
struct tm *tm;
int i, start, stop, forbit=0, comp;
clock = time (NULL);
tm = (struct tm *) localtime (&clock);
sprintf (buf, "%s/%s", LibDir, PERM_FILE);
if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL)
return 0;
while (fgets (buf, MAX_BUF, fp)) {
if (!strncmp (buf, "msg", 3)) {
if (forbit)
while (fgets (buf, MAX_BUF, fp)) /* print message */
fputs (buf, logfile);
break;
} else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3) {
LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n");
continue;
}
for (i=0; i< 7; i++) {
if (!strncmp (buf, days[i], 3) && (tm->tm_wday == i) &&
(tm->tm_hour >= start) && (tm->tm_hour < stop))
forbit = 1;
}
}
close_and_delete(fp, comp);
return forbit;
#else
return 0;
#endif
}
/*
* do_specials() is a collection of functions to call from time to time.
*/
void do_specials() {
static int special_count = 0, special2 = 0;
if(++special_count < 500)
return;
special_count = 0;
special2++;
flush_old_maps(); /* Clears the tmp-files of maps which have reset */
#if 0
#ifdef DEBUG_MALLOC_LEVEL
if (!malloc_verify())
LOG(llevError,"Warning - heap is corrupted\n");
else
LOG(llevDebug,"Heap checks out OK.\n");
#endif
#endif
if(!(special2%5)) {
fix_weight(); /* Hack to fix weightproblems caused by bugs */
if (!(special2%25))
fix_luck();
}
}
/*
* last_time is when the last tick was executed.
* We don't need to know the timezone since we're only interested in
* the delta time since the last 'tick' .
*/
struct timeval last_time;
struct timezone dummy_timezone;
int main(int argc,char **argv,char **env) {
/*
* Set up some global pointers, to make things easy:
*/
gargc=argc, gargv=argv, genv=env;
#ifdef DEBUG_MALLOC_LEVEL
malloc_debug(DEBUG_MALLOC_LEVEL);
#endif
init();
for(;;) {
nroferrors = 0;
#ifdef LONGJUMP
setjmp(jump_addr);
#endif
check_socket(); /* Check for new connections/data */
doeric_server();
process_events(NULL); /* "do" something with objects with speed */
check_active_maps(); /* Removes unused maps after a certain timeout */
do_specials(); /* Routines called from time to time. */
sleep_delta();
}
}